library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;


entity instruction_fetch is
generic( numBit	: integer := 32;
			opSize	: integer := 6;
			regSize	: integer := 5;
			romSize	: integer := 256);
port(	clk		: in  std_logic;
		rst		: in  std_logic;
		enb		: in  std_logic;
		en_start	: in  std_logic;
		PC_in	 	: in  std_logic_vector (numBit-1 downto 0);
		opcode 	: out std_logic_vector (opSize-1 downto 0);
		r_s 		: out std_logic_vector (regSize-1 downto 0);
		r_t 		: out std_logic_vector (regSize-1 downto 0);
		r_d 		: out std_logic_vector (regSize-1 downto 0);
		Imm 		: out std_logic_vector (numBit/2-1 downto 0);
		shamt  	: out std_logic_vector (regSize-1 downto 0);
		func  	: out std_logic_vector (opSize-1 downto 0);
		NPC_out	: out std_logic_vector (numBit-1 downto 0)
);
end instruction_fetch;

architecture Structural of instruction_fetch is 
component reg is
generic (N : integer := 32);
port( clock		: in  std_logic;
		reset		: in  std_logic;
		enable	: in  std_logic;
		data_in 	: in  std_logic_vector (N-1 downto 0);
		data_out : out std_logic_vector (N-1 downto 0)
);
end component;

component ROM is
    generic (		N_DATA	: natural := 32;
			N_ROWS	: natural := 48;
			N_COLS	: natural := 8 );
port( 	address		: in   STD_LOGIC_VECTOR (N_DATA-1 downto 0);
		Instruction	: out STD_LOGIC_VECTOR (N_DATA-1 downto 0)
);
end component;

component four_adder is
generic (N : integer := 32);
port(	data_in  : in  std_logic_vector (N-1 downto 0);
		data_out : out std_logic_vector (N-1 downto 0)
);
end component;

component Instr_reg is
generic( numBit	: integer := 32;
			opSize	: integer := 6;
			regSize	: integer := 5);
port( clock		: in  std_logic;
		reset		: in  std_logic;
		enable	: in  std_logic;
		data_in 	: in  std_logic_vector (numBit-1 downto 0);
		opcode 	: out std_logic_vector (opSize-1 downto 0);
		r_s 		: out std_logic_vector (regSize-1 downto 0);
		r_t 		: out std_logic_vector (regSize-1 downto 0);
		r_d 		: out std_logic_vector (regSize-1 downto 0);
		Imm 		: out std_logic_vector (numBit/2-1 downto 0);
		shamt  	: out std_logic_vector (regSize-1 downto 0);
		func  	: out std_logic_vector (opSize-1 downto 0)
);
end component;

signal pc_out	 : std_logic_vector (numBit-1 downto 0) := (others => '0');
signal adder_out: std_logic_vector (numBit-1 downto 0) := (others => '0');
signal IRmem_out: std_logic_vector (numBit-1 downto 0) := (others => '0');
begin

PC: reg generic map(numBit) port 
map (clk, rst, en_start, PC_in, pc_out);

Adder4: four_adder generic map(numBit) port
map (pc_out, adder_out);

NPC: reg generic map(numBit) port
map (clk, rst, enb, adder_out, NPC_out);

MEM: entity work.ROM(Behav32) generic 
map ( N_DATA => numBit,
		N_ROWS => romSize,
		N_COLS => numBit/4 ) port
map (  address => pc_out,
	   instruction    => IRmem_out
);

IR: Instr_reg generic
map ( numBit  => numBit,
		opSize  => opSize,
		regSize => regSize ) port
map ( clock		=> clk,
		reset		=> rst,
		enable	=> enb,
		data_in 	=> IRmem_out,
		opcode 	=> opcode,
		r_s 		=> r_s,
		r_t 		=> r_t,
		r_d 		=> r_d,
		Imm 		=> Imm,
		shamt  	=> shamt,
		func  	=> func
);

end Structural;

--configuration CFG_IF_32 of instruction_fetch is
--	for Structural
--		for MEM : ROM
--			use entity work.ROM(Behav32);
--		end for;
--	end for;
--end CFG_IF_32;
--
--configuration CFG_IF_64 of instruction_fetch is
--	for Structural
--		for MEM : ROM
--			use entity work.ROM(Behav64);
--		end for;
--	end for;
--end CFG_IF_64;
